#include "tcp_handler.h"
#include "shmem.h"
#include "msg_queue.h"


Client clients[MAX_CLIENTS];            // 保存来连接的单片机客户端信息

int msq_id = -1;                 // 消息队列id

int heartbeat_client_fd = -1;    // 发送心跳包的客户端套接字


// 共享内存信息
struct shmem_param shmem_info;     

// 客户端连接互斥锁
pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;  
// 共享内存写入互斥锁
pthread_mutex_t shmem_mutex = PTHREAD_MUTEX_INITIALIZER;
// 心跳包互斥锁
pthread_mutex_t heartbeat_mutex = PTHREAD_MUTEX_INITIALIZER;





// 处理单片机客户端
void* handle_client_pthread(void* arg);

// 接收消息队列消息， 发送给mcu
void* recvmsg_to_mcu_pthread(void* arg);

// 创建连接设备搜索子线程
void* create_client_pthread(void* arg);


// 循环等待客户端连接
int loop_main(int server_fd);

// 向设备搜索进程发送心跳包
void send_heartbeat_to_ds(const char *ip , unsigned short port);







int main(int argc, char const *argv[])
{
    printf("单片机处理进程启动: \n");

    // 初始化客户端数组
    for (int i = 0; i < MAX_CLIENTS; i++) 
    {
        clients[i].active = 0;
    }

    // 1. 启动 tcp 服务器
    int server_fd = create_server(TCP_SER_IP, TCP_SER_PORT);
    if(-1 == server_fd)
    {
        return -1;
    }
    printf("tcp 服务器启动成功， [server_fd = %d]\n", server_fd);


    // 创建子线程，启动 tcp 客户端， 连接到设备搜索进程
    pthread_t client_tid;
    if(0 != pthread_create(&client_tid, NULL, create_client_pthread, NULL))
    {
        printf("创建连接设备搜索子线程失败！\n");
        close(server_fd);
        return -1;
    }

    // 3. 初始化共享内存
    if(-1 == shmem_init(&shmem_info, SHMEM_NAME, SHMEM_SIZE))
    {
        printf("初始化共享内存失败\n");
        close(server_fd);
        return -1;
    }
    printf("初始化共享内存成功， [shmem_id = %d]\n", shmem_info.id);

    // 4. 初始化消息队列
    msq_id = msg_queue_init(MSG_QUEUE_NAME);
    if(-1 == msq_id)
    {
        printf("初始化消息队列失败\n");
        close(server_fd);
        return -1;
    }
    printf("初始化消息队列成功， [msq_id = %d]\n", msq_id);




    // 创建子线程，从消息队列读取消息，发送给单片机
    pthread_t msq_tid;
    if(0 != pthread_create(&msq_tid, NULL, recvmsg_to_mcu_pthread, NULL))
    {
        printf("创建消息队列子线程失败！\n");
        close(server_fd);
        return -1;
    }

    
    


    // 循环等待客户端连接 
    if(-1 == loop_main(server_fd))
    {
        ERROR("loop_main");
        close(server_fd);
        exit(-1);
    }


    return 0;
}


// 循环等待客户端连接
int loop_main(int server_fd)
{
    while (1)
    {
        struct sockaddr_in client_addr;     // 用来接收客户端的地址信息
        int len = sizeof(client_addr);      // 用来接收保存地址信息的结构体的长度            

        // 阻塞等待客户端连接
        int act_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len);
        if(-1 == act_fd)
        {
            ERROR("accept");
            return -1;
        }

        // 为客户端分配槽位
        int client_index = -1;
        pthread_mutex_lock(&clients_mutex);
        for (int i = 0; i < MAX_CLIENTS; i++) 
        {
            if (!clients[i].active) 
            {
                client_index = i;
                clients[i].socket = act_fd;
                clients[i].address = client_addr;
                clients[i].active = 1;
                break;
            }
        }
        pthread_mutex_unlock(&clients_mutex);

        if(-1 == client_index)
        {
            printf("客户端连接数量达到最大限制！\n");
            close(act_fd);
            return -1;
        }

        // 为客户端分配线程
        int pthread_ret = pthread_create(&clients[client_index].tid, NULL, handle_client_pthread, &client_index);
        if(0 != pthread_ret)        // 创建线程失败
        {
            ERROR("pthread_create");
            close(act_fd);
            return -1;
        }

    }// while end

}// loop_main end




void* handle_client_pthread(void* arg)
{
    // 设置线程为分离态
    pthread_detach(pthread_self());

    // 解析客户端信息
    int client_index = *(int*)arg;
    Client *client = &clients[client_index];
    char buf[BUF_SIZE];


    // 获取单片机ip和端口号
    char client_ip[32];
    inet_ntop(AF_INET, &(client->address.sin_addr), client_ip, INET_ADDRSTRLEN);

    int client_port = ntohs(client->address.sin_port);

    printf("[server]: client[%s %d] connection successful!\n", client_ip, client_port);
    printf("[server]: act_fd : %d\n", client->socket);

    // 接收单片机数据
    ssize_t recv_len;
    while ((recv_len = recv(client->socket, buf, BUF_SIZE - 1, 0)) > 0) 
    {
        buf[recv_len] = '\0';
        printf("From MCU [id=%d]: %s\n", client_index, buf);  // 打印数据


        pthread_mutex_lock(&shmem_mutex);

        // 写入共享内存（保留原有功能）
        shmem_write(&shmem_info, buf, recv_len);

        pthread_mutex_unlock(&shmem_mutex);



        // 每次接收数据都发送IP和端口给 设备搜索进程
        send_heartbeat_to_ds(client_ip, client_port);
    }


    pthread_exit(NULL);
}


void* recvmsg_to_mcu_pthread(void* arg)
{
    // 设置线程为分离态
    pthread_detach(pthread_self());

    struct Msg msg;
    ssize_t recv_len;

    while(1)
    {
        recv_len = msg_queue_recv(msq_id, (void*)&msg, sizeof(msg.buf), MSG_QUEUE_TYPE, 0);
        if(recv_len <= 0)
        {
            printf("接收数据失败， 重新等待接收！\n");
            continue;  
        }

        printf("%s\n", msg.buf);


        // 2. 发送数据给所有活跃的单片机客户端
        for (int i = 0; i < MAX_CLIENTS; i++) 
        {
            if (clients[i].active) 
            {  
                // 仅发送给活跃客户端
                pthread_mutex_lock(&clients_mutex);  // 保护客户端列表

                // 向单片机发送数据
                send(clients[i].socket, msg.buf, strlen(msg.buf), 0);
                printf("Sent to MCU %d: %s\n", i, msg.buf);

                pthread_mutex_unlock(&clients_mutex);
            }
        }
        
    }


    pthread_exit(NULL);
}


void* create_client_pthread(void* arg)
{
    // 设置线程为分离态
    pthread_detach(pthread_self());

    while(1)
    {
        if(heartbeat_client_fd == -1)
        {
            pthread_mutex_lock(&heartbeat_mutex);

            // 2. 启动 tcp 客户端， 连接到设备搜索进程
            heartbeat_client_fd = create_client(TCP_CLI_IP, TCP_CLI_PORT);
            if(-1 == heartbeat_client_fd)
            {
                ERROR("create_client");
                pthread_mutex_unlock(&heartbeat_mutex);
                sleep(1);
                continue;
            }
            printf("tcp 客户端连接成功， [heartbeat_client_fd = %d]\n", heartbeat_client_fd);
            pthread_mutex_unlock(&heartbeat_mutex);
        }
        

    }

    pthread_exit(NULL);
}

void send_heartbeat_to_ds(const char *ip , unsigned short port)
{
    pthread_mutex_lock(&heartbeat_mutex);

    // 格式化要发送的IP和端口号
    char data[BUF_SIZE];
    snprintf(data, BUF_SIZE, "%s:%d", ip, port); 

    if(-1 == send(heartbeat_client_fd, data, strlen(data), 0))
    {
        perror("Failed to send IP:Port");
        close(heartbeat_client_fd);  // 发送失败，下次重连
        heartbeat_client_fd = -1;
    }
    else
    {
        printf("Sent to QT TCP: %s (IP:Port)\n", data);
    }

    pthread_mutex_unlock(&heartbeat_mutex);
}